import { BaseRequestConfig } from './types';
import { ConfigUtils } from './ConfigUtils';

export interface UploaderConfig extends BaseRequestConfig {
  // Uploader 特有配置可以在这里添加
}

export interface UploadOptions extends BaseRequestConfig {
  body?: FormData | Blob | ArrayBuffer | string;
}

export class Uploader {
  private defaultConfig: UploaderConfig;

  constructor(config: UploaderConfig = {}) {
    this.defaultConfig = config;
  }

  async upload(
    url: string | URL,
    data: FormData | Blob | ArrayBuffer | string,
    options: UploadOptions = {}
  ): Promise<Response> {
    const config = ConfigUtils.mergeConfigs<UploadOptions>(
      this.defaultConfig,
      options,
      { body: data }
    );
    return this.fetchWithXHR(url, config);
  }

  private fetchWithXHR(
    url: string | URL,
    config: UploadOptions
  ): Promise<Response> {
    return new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest();
      xhr.open('POST', url.toString(), true);

      // 设置请求头
      const headers = config.headers || {};
      Object.entries(headers).forEach(([key, value]) => {
        xhr.setRequestHeader(key, String(value));
      });

      // 设置超时时间
      const timeout = config.timeout;
      if (timeout && timeout > 0) {
        xhr.timeout = timeout;
      }

      xhr.responseType = 'blob';

      // 设置上传进度回调
      const onUploadProgress = config.onUploadProgress;
      if (onUploadProgress && xhr.upload) {
        xhr.upload.addEventListener('progress', onUploadProgress);
      }

      xhr.addEventListener('load', () => {
        const headers = this.parseResponseHeaders(xhr.getAllResponseHeaders());
        const response = new Response(xhr.response, {
          status: xhr.status,
          statusText: xhr.statusText,
          headers,
        });
        resolve(response);
      });

      xhr.addEventListener('error', () => reject(new Error('Network error')));
      xhr.addEventListener('timeout', () =>
        reject(new Error('Request timeout'))
      );

      if (config.signal) {
        config.signal.addEventListener('abort', () => {
          xhr.abort();
          reject(new Error('Request aborted'));
        });
      }

      let body: XMLHttpRequestBodyInit | Document | null = null;
      if (config.body) {
        if (config.body instanceof ReadableStream) {
          reject(
            new Error(
              'ReadableStream not supported with progress monitoring, use fetch instead'
            )
          );
          return;
        } else {
          body = config.body as XMLHttpRequestBodyInit | Document;
        }
      }
      xhr.send(body);
    });
  }

  private parseResponseHeaders(headersString: string): Record<string, string> {
    const headers: Record<string, string> = {};
    if (!headersString) return headers;
    headersString.split('\r\n').forEach((line) => {
      const parts = line.split(': ');
      if (parts.length === 2) {
        headers[parts[0].toLowerCase()] = parts[1];
      }
    });
    return headers;
  }

  static create(config: UploaderConfig = {}): Uploader {
    return new Uploader(config);
  }
}

export const uploader = new Uploader();
